﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SqlLibrary;
using Ecopsy.DataTier;
using AgencyEntityLib.BaseEntity;

namespace SqlLibrary
{
    
   /// <summary>
   /// Базовый класс по загрузке списков - по умолчанию строит предложение позволяющее отфильтровать по указанному 
   /// v_propertyOf
   /// Правила формирования:
   /// На основании vPropertyOfList - первый запрос формирующий выборку из v_propertyOf
   /// Из полученной выборки нолько то что указанно в FilterList
   /// На результат - разобрать лексему - получить предложение , побить на странички - выдать.    
   /// </summary>
 
   public  class ListLoadStatment : SqlStatment
    {

       public ListLoadStatment() { }
       public ListLoadStatment(string FindString) : base(FindString) { }

        protected  int _StartRowIndex=0;
        protected int _EndRowIndex = 100;

        /// <summary>
        /// Paging StartRowIndex
        /// </summary>
        public int StartRowIndex {get {return _StartRowIndex; } set{_StartRowIndex =value ;}}
        /// <summary>
        /// Paging EndRowIndex
        /// </summary>
        public int EndRowIndex { get { return _EndRowIndex; } set { _EndRowIndex = value; } }
 
       /// <summary>
       /// Нименование vPropertyOf (вьюха ресурс свойств)
       /// </summary>
        public virtual string vPropertyOf_ViewName { get { return string.Empty; } }

       /// <summary>
       /// Вьюха ресурс данных
       /// </summary>
       public virtual string  Source_ViewName
       {
           get { return string.Empty; }
       }

       /// <summary>
       /// Запускает последовательность
       /// GetPropertyOfSql() + GetNotPropertyOfString() + GetResultSetSql() + GetPageSql() + GetResultToXmlVarible();
       /// </summary>
       /// <returns></returns>
       public   override string GetStatment()
        {
            return GetPropertyOfSql() + GetNotPropertyOfString() + GetResultSetSql() + GetPageSql() + GetResultToXmlVarible();
        }

       ///// <summary>
       ///// Первый срез по vPropertyOf на выходе #SelectList - перечень ид соответсв. первому срезу
       ///// </summary>
       ///// <returns></returns>
       //protected virtual string GetPropertyOfSql()
       // {

       //     string where = base.BuildStatment ();
       //     string[] cond= Lexeme.Split(" ".ToCharArray()[0]);  

       //     if (where.Length == 0) return " select Id into #SelectList  from  "+Source_ViewName;

       //     string sql = " select Id into #SelectList  from" +
       //       "(" +
       //       "select " +
       //           vPropertyOf_ViewName + ".ID as ID," +
       //           "1 as ItemCount " +
       //       "from " +
       //           vPropertyOf_ViewName +
       //       " where 	" +
       //        where +
       //           ") as res   " +
       //       "group by res.ID,ItemCount " +
       //       "having sum(ItemCount)= " +this.ChildNodes.Count.ToString();

       //     return sql;

       // }

       protected virtual string GetPropertyOfSql()
       {
           string where = base.BuildStatment();
           string sql = string.Empty;           

           //1) Сформировать #FilterList - набор итоговых ид из переменной xml
           FilterList.Reset();
           if (FilterList.Count > 0) //  есть четко обозначеный список ограничений - _FilterList>0 делаем срез по нему 
           {
               //#FilterList
               sql = sql+"declare @FilterList_xml as xml set @FilterList_xml=' " + FilterList.ToXml(true) + "'";
               sql = sql + " SELECT  T.c.value('(@ID)[1]','varchar(36)') as ID INTO #FilterList FROM    @FilterList_xml.nodes('/EntityList/EntitySingle') T(c)";               
            }

           //2) Наложить ограничения по наборам параметр|значение (если был шаг 1 то на его результат - нет на vPropertyOf_ViewName)
           if (ParamValueList.Count > 0) // есть ограничения по парам параметр-значение 
           {
               //##ParamValueList
               sql =sql+ _ParamValueListBox.GetSqlForTable("#ParamValueList");// получаем второй срез на основании vPropertyOfList (запрос по парам парметр,значение)
            
           }

           //3) Сливаем списки ограничения если были
           bool bHaveInLists = false; // есть ограничения внешним списком или набором параметов ?
           bHaveInLists = (FilterList.Count + ParamValueList.Count) > 0;

           if(bHaveInLists)
               sql = sql + "select top 0 id into #SourcePropOf  from "+Source_ViewName ;
           
           if (FilterList.Count > 0)
               sql = sql + " insert into #SourcePropOf select id from #FilterList ";

           if (ParamValueList.Count > 0)
           {
               sql = sql + " insert into #SourcePropOf select #ParamValueList.id from #ParamValueList ";
               if (FilterList.Count > 0) sql = sql + " join #FilterList on #FilterList.id=#ParamValueList.id ";
           }

           string _Source_ViewName = " #SourcePropOf";
           if (FilterList.Count == 0 && ParamValueList.Count == 0)
               _Source_ViewName = Source_ViewName;
                      

           if (where.Length == 0)  //нет лексемы?                  
           {
               return sql + " select distinct Id into #SelectList  from  " + (bHaveInLists?_Source_ViewName:Source_ViewName);
           }

           ///есть лексема - добираем запрос согласно лексеме           

           //a) Если были внеш ограничения - режем vPropertyOf_ViewName
           if (bHaveInLists)
           {
               sql = sql + " select " + vPropertyOf_ViewName + ".* into #vPropertyOf_ViewName from " + vPropertyOf_ViewName + " join  #SourcePropOf on " + vPropertyOf_ViewName + ".id = #SourcePropOf.id ";
               
           }

           sql = sql + " select Id into #SelectList  from" +
            "(" +
            "select " + (bHaveInLists ? "#vPropertyOf_ViewName" : vPropertyOf_ViewName) + ".ID as ID," +
                "1 as ItemCount " +
            "from " + (bHaveInLists ? "#vPropertyOf_ViewName" : vPropertyOf_ViewName) +
            " where 	" +
             where +
                ") as res   " +
            "group by res.ID,ItemCount " +
            "having sum(ItemCount)= " + this.ChildNodes.Count.ToString();
           return sql;
       }

       /// <summary>
       /// Формирование условия where - отрицания значений
       /// </summary>
       /// <returns></returns>
       protected virtual string GetNotPropertyOfString()
        {
            string w=GetNotStatment();
            if(w.Length ==0) return string .Empty ;
            return " delete from #SelectList where id in (select id from " + vPropertyOf_ViewName + " where " + w + ") ";
        }

       /// <summary>
       /// скрипт по вычислению реально отобранных величин 
       /// </summary>
       /// <returns></returns>
       protected virtual string GetResultSetSql()
        {
            return " declare @r_count int select "+Source_ViewName + ".ID,[XML] into 	#ResultSet from " + Source_ViewName + " join #SelectList on " +Source_ViewName + ".ID=#SelectList.Id DECLARE @OutputRwCnt  INT select @OutputRwCnt=count(*) from #ResultSet ";
        }

       /// <summary>
       /// Формирование странички 
       /// </summary>
       /// <returns></returns>
       protected virtual string GetPageSql()
        { 
            return " select 	[XML] into 	#Page from ( select ID, [XML] , ROW_NUMBER() OVER (ORDER BY ID) AS row_num  from #ResultSet) as Page where row_num between "+ _StartRowIndex.ToString()  + " and "+_EndRowIndex.ToString () ;
        }

       /// <summary>
       /// Преобразование результата в xml переменную 
       /// </summary>
       /// <returns></returns>
       protected virtual string GetResultToXmlVarible()
        {
            return 
           " declare @r as xml select @r=(select [xml].query('.') from 	#Page FOR XML PATH(''), TYPE, ELEMENTS , ROOT('EntityList') )"+
            " if not(@r is null)   SET @r.modify('insert attribute OutputRwCnt {sql:variable(''@OutputRwCnt'')} into (/EntityList)[1]')" +            
            " select @r";
        }

       private EntityList _FilterList = new EntityList();
       public EntityList FilterList
       {
           get
           {
               return _FilterList;
           }
           set { _FilterList = value; }
       }

       
       public vPropertyOfList _ParamValueListBox = new vPropertyOfList();
       
       /// <summary>
       /// Набор пар = параметр значение, сформировать запрос к 
       /// Коллекция - vPropertyOfList.ParamListItem
       /// </summary>       
       public EntityList ParamValueList
       {
           
           get { _ParamValueListBox.ViewName = vPropertyOf_ViewName; return _ParamValueListBox.ParamList; }
       }

       /// <summary>
       /// Опция - указывающя как формирвать запрос по коллекции ParamValueList
       /// парметр/значение, параметр, значение
       /// </summary>
       public vPropertyOfList.Options ParamValueList_SearchOption
       {
           get { return _ParamValueListBox.SqlSearchOption;  }
           set { _ParamValueListBox.SqlSearchOption = value; }
       }

    }
}
